package com.gcloud.controller.network.service.impl;

import com.gcloud.controller.ResourceProviders;
import com.gcloud.controller.network.dao.NetworkDao;
import com.gcloud.controller.network.dao.RouterDao;
import com.gcloud.controller.network.dao.SubnetDao;
import com.gcloud.controller.network.entity.Network;
import com.gcloud.controller.network.entity.Router;
import com.gcloud.controller.network.entity.Subnet;
import com.gcloud.controller.network.model.DescribeVRoutersParams;
import com.gcloud.controller.network.provider.IRouterProvider;
import com.gcloud.controller.network.service.IRouterService;
import com.gcloud.core.exception.GCloudException;
import com.gcloud.framework.db.PageResult;
import com.gcloud.header.api.model.CurrentUser;
import com.gcloud.header.enums.ResourceType;
import com.gcloud.header.network.model.VRouterSetType;
import com.gcloud.header.network.msg.api.CreateVRouterMsg;
import com.gcloud.header.network.msg.api.DeleteVRouterMsg;
import com.gcloud.header.network.msg.api.ModifyVRouterAttributeMsg;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class RouterServiceImpl implements IRouterService {
    @Autowired
    private RouterDao vRouterDao;

    @Autowired
    private SubnetDao subnetDao;
    
    @Autowired
    private NetworkDao networkDao;

    @Override
    public PageResult<VRouterSetType> describeVRouters(DescribeVRoutersParams params, CurrentUser currentUser) {
        if (params == null) {
            params = new DescribeVRoutersParams();
        }
        return vRouterDao.describeVRouters(params, VRouterSetType.class, currentUser);
    }

    @Override
    public String createVRouter(CreateVRouterMsg msg) {
        return this.getProviderOrDefault().createVRouter(msg);
    }

    @Override
    public Router getVRouterById(String vRouterId) {
        return vRouterDao.getById(vRouterId);
    }

    @Override
    public void deleteVRouter(DeleteVRouterMsg msg) {
        Router router = vRouterDao.getById(msg.getvRouterId());
        if (null == router) {
            throw new GCloudException("0020402::找不到该路由器");
        }
        vRouterDao.deleteById(msg.getvRouterId());
        this.checkAndGetProvider(router.getProvider()).deleteVRouter(router.getProviderRefId());
    }

    @Override
    public void modifyVRouterAttribute(ModifyVRouterAttributeMsg msg) {
        Router router = vRouterDao.getById(msg.getvRouterId());
        if (router == null) {
            throw new GCloudException("0020203::修改失败，找不到该路由器");
        }
        List<String> updatedField = new ArrayList<String>();
        updatedField.add(router.updateName(msg.getvRouterName()));
        updatedField.add(router.updateUpdatedAt(new Date()));
        vRouterDao.update(router);
        this.checkAndGetProvider(router.getProvider()).modifyVRouterAttribute(router.getProviderRefId(), msg.getvRouterName());
    }

    @Override
    public void setVRouterGateway(String vRouterId, String vpcId) {
        Router router = vRouterDao.getById(vRouterId);
        if (router == null) {
            throw new GCloudException("0020503::找不到该路由器");
        }

        Network network = networkDao.getById(vpcId);
        if (network == null) {
            throw new GCloudException("0020504::找不到该网络");
        }
        this.checkAndGetProvider(router.getProvider()).setVRouterGateway(router.getProviderRefId(), network.getProviderRefId());

    }

    @Override
    public void cleanVRouterGateway(String vRouterId) {
        Router router = vRouterDao.getById(vRouterId);
        if (router == null) {
            throw new GCloudException("0020602::找不到该路由器");
        }
        List<String> updatedField = new ArrayList<String>();
        updatedField.add(router.updateExternalNetworkId(null));
        updatedField.add(router.updateUpdatedAt(new Date()));
        vRouterDao.update(router, updatedField);
        this.checkAndGetProvider(router.getProvider()).cleanVRouterGateway(router.getProviderRefId());
    }

    @Override
    public void attachVSwitchVRouter(String routerId, String subnetId) {
        Router router = vRouterDao.getById(routerId);
        if (router == null) {
            throw new GCloudException("0020703::找不到该路由器");
        }
        Subnet subnet = subnetDao.getById(subnetId);
        if (subnet == null) {
            throw new GCloudException("0020704::找不到该交换机");
        }
        List<String> updatedField = new ArrayList<String>();
        updatedField.add(subnet.updateRouterId(routerId));
        updatedField.add(router.updateUpdatedAt(new Date()));
        subnetDao.update(subnet, updatedField);
        this.checkAndGetProvider(router.getProvider()).attachSubnetRouter(router.getProviderRefId(), subnet.getProviderRefId());
    }

    @Override
    public void detachVSwitchVRouter(String routerId, String subnetId) {
    	detachVSwitchVRouter(routerId, subnetId, null);
    }
    
    @Override
    public void detachVSwitchVRouter(String routerId, String subnetId, String portId) {
        Router router = vRouterDao.getById(routerId);
        if (router == null) {
            throw new GCloudException("0020803::找不到该路由器");
        }
        Subnet subnet = subnetDao.getById(subnetId);
        if (subnet == null) {
            throw new GCloudException("0020804::找不到该交换机");
        }
        List<String> updatedField = new ArrayList<String>();
        updatedField.add(subnet.updateRouterId(null));
        updatedField.add(router.updateUpdatedAt(new Date()));
        subnetDao.update(subnet, updatedField);
        this.checkAndGetProvider(router.getProvider()).detachSubnetRouter(router.getProviderRefId(), subnet.getProviderRefId(), portId);
    }

    private IRouterProvider getProviderOrDefault() {
        IRouterProvider provider = ResourceProviders.getDefault(ResourceType.ROUTER);
        return provider;
    }

    private IRouterProvider checkAndGetProvider(Integer providerType) {
        IRouterProvider provider = ResourceProviders.checkAndGet(ResourceType.ROUTER, providerType);
        return provider;
    }

}
